﻿using SharpNoisePCL.Helpers;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace SharpNoisePCL.Noise
{
    public class ValueNoise : INoiseGenerator
    {
        float[] RandomArray1D;
        float[,] RandomArray2D;

        private int arraySize;

        public ValueNoise()
        {
            arraySize = 256; // Default Value
        }
               
        public int ArraySize
        {
            get { return arraySize; }
            set { arraySize = value; }
        }


        private void InitArray1D()
        {
            RandomArray1D = new float[ArraySize];
            Random r = new Random();
            for (int i = 0; i < ArraySize; i++)
            {
                RandomArray1D[i] = (float)r.NextDouble();
            }
        }

        private void InitArray2D()
        {
            RandomArray2D = new float[ArraySize, ArraySize];
            Random r = new Random();
            for (int i = 0; i < ArraySize; i++)
            {
                for (int j = 0; j < ArraySize; j++)
                {
                    RandomArray2D[i, j] = (float)r.NextDouble();
                }
            }
        }
        
        public float Get1D(float x)
        {
            if (RandomArray1D == null)
            {
                InitArray1D();
            }

            int xmin = (int)(Math.Floor(x) % this.RandomArray1D.Length);
            float t = x - xmin;
            return Interpolaters.Linear(RandomArray1D[xmin], RandomArray1D[xmin + 1], t);
        }

        public float Get2D(float x, float y)
        {
            if (RandomArray2D == null) InitArray2D();

            int xmin =  (int)(Math.Floor(x) % this.ArraySize);
            int ymin = (int)(Math.Floor(y) % this.ArraySize);

            double tx = x - xmin;
            double ty = y - ymin;

            /// Random values at the corners of the cell
            int rx0 = (int)(xmin & (this.ArraySize - 1));
            int rx1 = (int)((xmin + 1) & (this.ArraySize - 1));
            int ry0 = (int)(ymin & (this.ArraySize - 1));
            int ry1 = (int)((ymin + 1) & (this.ArraySize - 1));

            float sx = (int)(tx * tx * (3 - (2 * tx)));
            float sy = (int)(ty * ty * (3 - (2 * ty)));

            float p00 = this.RandomArray2D[rx0,ry0];
            float p01 = this.RandomArray2D[rx0,ry1];
            float p10 = this.RandomArray2D[rx1,ry0];
            float p11 = this.RandomArray2D[rx1,ry1];

            var pl0 = Interpolaters.Linear(p00, p10, sx);
            var pl1 = Interpolaters.Linear(p01, p11, sx);

            return Interpolaters.Linear(pl0, pl1, sy);            
        }
               
        public float Get3D(float x, float y, float z)
        {
            throw new NotImplementedException();
        }

        public float Get4D(float x, float y, float z, float t)
        {
            throw new NotImplementedException();
        }
    }
}
